package cn.sccl.dirms.topo.discovery;

import cn.sccl.dirms.topo.discovery.model.DeviceInfo;
import cn.sccl.dirms.topo.discovery.model.DiscoveryConfig;
import cn.sccl.dirms.topo.discovery.model.IpRange;
import cn.sccl.dirms.topo.discovery.model.LinkInfo;
import cn.sccl.dirms.topo.discovery.service.DiscoveryRelationService;
import cn.sccl.dirms.topo.discovery.service.MapValueComparator;
import cn.sccl.dirms.topo.discovery.util.ComUtil;
import cn.sccl.dirms.topo.snmp.util.SNMPConfig;

import java.util.*;

/**
 * Created by julei on 2017/9/12.
 */
public class DiscoveryAPI {
    /**
     * 发现设备
     *
     * @param rangeList
     * @param snmpConfigList
     * @return
     */
    public static List<DeviceInfo> ipRangeDeiscovery(List<IpRange> rangeList, List<SNMPConfig> snmpConfigList) {
        Discovery impl = new Discovery();
        List<String> ips = ComUtil.getIPSByRangeList(rangeList);
        DiscoveryConfig discoveryConfig = new DiscoveryConfig();
        List<DeviceInfo> deviceInfoList = impl.discoveryDevicesByIps(1000, ips, snmpConfigList, discoveryConfig);
        impl.getDevList().addAll(deviceInfoList);
        //转发表再发现
        //impl.discoveryChildren(deviceInfoList, snmpConfigList, discoveryConfig);
        return impl.getDevList();
    }


    /**
     * 发现链路
     *
     * @param deviceInfoList
     * @param discoveryConfig
     * @return
     */
    public static List<LinkInfo> linkDeiscovery(List<DeviceInfo> deviceInfoList, DiscoveryConfig discoveryConfig) throws InterruptedException {
        //创建链路
        DiscoveryRelationService relation = new DiscoveryRelationService();
        //发现原始关联关系
        List<LinkInfo> linkInfoList = relation.createAllLinks(deviceInfoList, discoveryConfig);
        //        //生成链路树
        //        if(linkInfoList!=null&&linkInfoList.size()>1){
        //            linkInfoList = generateLinkTree(linkInfoList);
        //        }
        //        //梳理链路端口，
        //        linkInfoList = washLink(linkInfoList);
        return linkInfoList;
    }

    /**
     * 将vlan类型端口落实到实际物理端口上，消除1端口对多设备问题
     *
     * @param linkInfoList
     * @return
     */
    public static List<LinkInfo> washLink(List<LinkInfo> linkInfoList) {
        //获取
        return  linkInfoList;
    }


        /**
         * 生成链路树
         *
         * @param linkInfoList
         * @return
         */
    public static List<LinkInfo> generateLinkTree(List<LinkInfo> linkInfoList) {
        List<LinkInfo> result = new ArrayList<LinkInfo>();
        Map<String, List<String>> ipLinkListMap = new LinkedHashMap<String, List<String>>();
        Map<String, LinkInfo> ipPortMap = new LinkedHashMap<String, LinkInfo>();
        Map<String, Integer> ipNodeNumMap = new LinkedHashMap<String, Integer>();
        for (LinkInfo linkInfo : linkInfoList) {
            String startIp = linkInfo.startDevice.getDeviceIP();
            String endIp = linkInfo.endDevice.getDeviceIP();
            List<String> ipLink = ipLinkListMap.get(startIp);
            Integer nodeNum = ipNodeNumMap.get(startIp);
            if(nodeNum==null){
                nodeNum = 0;
            }
            if (ipLink == null) {
                ipLink = new ArrayList<String>();
            }
            if (!ipLink.contains(endIp)) ipLink.add(endIp);
            ipLinkListMap.put(startIp, ipLink);
            ipNodeNumMap.put(startIp, nodeNum+1);

            ipLink = ipLinkListMap.get(endIp);
            nodeNum = ipNodeNumMap.get(endIp);
            if (ipLink == null) {
                ipLink = new ArrayList<String>();
            }
            if(nodeNum==null){
                nodeNum = 0;
            }
            if (!ipLink.contains(startIp)) ipLink.add(startIp);
            ipLinkListMap.put(endIp, ipLink);
            ipNodeNumMap.put(endIp,nodeNum+1);
            ipPortMap.put(startIp + "-" + endIp, linkInfo);
        }

        ipLinkListMap = sortMapByValue(ipLinkListMap);
        String maxIp = ipLinkListMap.keySet().toArray()[0].toString();
        List<String> parentSet = new ArrayList<String>();
        findTree(maxIp,ipLinkListMap,parentSet,result,ipPortMap);
        return result;
    }
    /**
     * 寻找树路径
     *
     * @param parentip
     * @param ipLinkListMap
     * @param parentSet
     * @param result
     * @param ipPortMap
     */
    public static void findTree(String parentip, Map<String, List<String>> ipLinkListMap, List<String> parentSet, List<LinkInfo> result, Map<String, LinkInfo> ipPortMap) {
        //往下一直找到叶子节点
        parentSet.add(parentip);
        List<String> list = ipLinkListMap.get(parentip);
        for (String findIp : list) {

            doDeapFind(findIp, ipLinkListMap, parentSet, result, ipPortMap);
        }
    }



    /**
     * 深度递归查找叶子节点
     *
     * @param findip
     * @param ipLinkListMap
     * @param parentSet
     * @param result
     * @param ipPortMap
     */
    public static void doDeapFind(String findip, Map<String, List<String>> ipLinkListMap, List<String> parentSet, List<LinkInfo> result, Map<String, LinkInfo> ipPortMap) {
        List<String> findList = ipLinkListMap.get(findip);
        if (findList == null) return;
        for (String pIp : findList) {
            if (pIp==null||parentSet.contains(pIp)) {
                continue;
            } else {
                parentSet.add(pIp);
                doDeapFind(pIp, ipLinkListMap, parentSet, result, ipPortMap);
            }
        }
        //全部父节点都在了
        //获取节点数最少的做为相邻连接
        String trueFather = "";
        int level = 99999;
        for (int i=0;i<findList.size();i++) {
            String pIp  = findList.get(i);
            List fatherList = ipLinkListMap.get(pIp);
            if (fatherList == null) {
                continue;
            }
            //去掉集合中该元素所有联通关系
            int number = fatherList.size();
            if (number < level) {
                trueFather = pIp;
                level = number;
            }
        }
        ipLinkListMap.remove(findip);
        LinkInfo link = ipPortMap.get(trueFather + "-" + findip);
        if (link == null) {
            link = ipPortMap.get(findip + "-" + trueFather);
        }
        result.add(link);
    }

    /**
     * 使用 Map按value进行排序
     *
     * @param oriMap
     * @return
     */
    public static Map<String, List<String>> sortMapByValue(Map<String, List<String>> oriMap) {
        if (oriMap == null || oriMap.isEmpty()) {
            return null;
        }
        Map<String, List<String>> sortedMap = new LinkedHashMap<String, List<String>>();
        List<Map.Entry<String, List<String>>> entryList = new ArrayList<Map.Entry<String, List<String>>>(
                oriMap.entrySet());
        Collections.sort(entryList, new MapValueComparator());

        Iterator<Map.Entry<String, List<String>>> iter = entryList.iterator();
        Map.Entry<String, List<String>> tmpEntry = null;
        while (iter.hasNext()) {
            tmpEntry = iter.next();
            sortedMap.put(tmpEntry.getKey(), tmpEntry.getValue());
        }
        return sortedMap;
    }
}
